package com.project.poetry.service.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.project.poetry.common.constant.ConstantValue;
import com.project.poetry.common.exception.ServiceException;
import com.project.poetry.common.job.QuartzUtil;
import com.project.poetry.common.util.CommonUtil;
import com.project.poetry.service.entity.dto.job.JobDTO;
import com.project.poetry.service.entity.po.job.JobPO;
import com.project.poetry.service.mapper.JobMapper;
import com.project.poetry.service.service.JobService;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.UUID;

/**
 * @author mengxj
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class JobServiceImpl implements JobService {

    @Resource
    private JobMapper jobMapper;

    @SneakyThrows
    @Override
    public void saveJob(JobPO job) {
        this.checkAndFormatJob(job);
        this.jobMapper.insert(job);
        QuartzUtil.createScheduler(job);
    }

    @SneakyThrows
    @Override
    public void updateJob(JobPO job){
        this.checkAndFormatJob(job);
        this.jobMapper.updateById(job);
        QuartzUtil.updateScheduler(job);
    }

    /**
     * 校验cron表达式
     * 校验入参的值
     * 校验jobId和group组成的唯一性
     * @param job job
     */
    private void checkAndFormatJob(JobPO job){
        String cronStr = job.getCronExpression();
        CommonUtil.checkThrow(cron -> !QuartzUtil.checkCron(cron), cronStr,
                ConstantValue.PARAM_ERROR_STATUS_CODE, String.format("cron 表达式 %s 错误！请输入合法的表达式！！！", cronStr));
        this.formatJob(job);
        String jobId = job.getJobId(), group = job.getJobGroup();
        int count = this.jobMapper.selectCount(
                new QueryWrapper<JobPO>().lambda().eq(JobPO :: getJobGroup, group).eq(JobPO::getJobId, jobId));
        CommonUtil.checkThrow(num -> num > 0, count, ConstantValue.PARAM_ERROR_STATUS_CODE,
                String.format("业务错误！组 %s 中已存在jobId为 %s 任务！请更换组名jobId", group, jobId));
    }

    /**
     * 校验job中的jobId以及group，空则生成对应值
     * @param job job
     */
    private void formatJob(JobPO job){
        if(StrUtil.isBlank(job.getJobId())){
            job.setJobId(UUID.randomUUID().toString());
        }
        job.setJobGroup(QuartzUtil.getRealGroup(job.getJobGroup()));
    }

    @SneakyThrows
    @Override
    public void pauseJob(Long jobId){
        JobPO po = this.jobMapper.selectById(jobId);
        QuartzUtil.pauseScheduler(po);
    }

    @SneakyThrows
    @Override
    public void resumeJob(Long jobId){
        JobPO po = this.jobMapper.selectById(jobId);
        QuartzUtil.resumeScheduler(po);
    }

    @SneakyThrows
    @Override
    public void deleteJob(Long jobId){
        JobPO po = this.jobMapper.selectById(jobId);
        QuartzUtil.deleteScheduler(po);
        this.jobMapper.deleteById(jobId);
    }

    @SneakyThrows
    @Override
    public void run(Long jobId){
        JobPO po = this.jobMapper.selectById(jobId);
        QuartzUtil.runScheduler(po);
    }

    @Override
    public IPage<JobPO> list(JobDTO job) {
        LambdaQueryWrapper<JobPO> wrapper = new QueryWrapper<JobPO>().lambda();
        String param;
        if(StrUtil.isNotBlank(param = job.getJobId())){
            wrapper.eq(JobPO::getJobId, param);
        }
        if(StrUtil.isNotBlank(param = job.getGroup())){
            wrapper.eq(JobPO::getJobGroup, param);
        }
        if(StrUtil.isNotBlank(param = job.getDesc())){
            wrapper.like(JobPO::getDescriptor, param);
        }
        Page<JobPO> page = CommonUtil.getPage(job.getPageNum(), job.getPageSize());
        return this.jobMapper.selectPage(page, wrapper);
    }
}
